package net.gillessed.icarus.swingui;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.swing.JPanel;

import net.gillessed.icarus.FlameModel;
import net.gillessed.icarus.Function;
import net.gillessed.icarus.geometry.Triangle;
import net.gillessed.icarus.geometry.ViewRectangle;

public class TransformEditPanel extends JPanel {
	private static final long serialVersionUID = -3230829210595250908L;
	private final ViewRectangle viewRectangle = new ViewRectangle(2, 1.0, this);
	private int triangleDragged;
	private int moveState;
	private Triangle baseTriangle;
	private List<Triangle> triangles;
	private FlameModel model;
	private int lastTouched;
	private final MouseListener mouseListener = new MouseListener() {
		@Override
		public void mouseReleased(MouseEvent e) {
			if(triangleDragged >= 0 ) {
				triangleDragged = - 1;
				moveState = 0;
			}
		}
		
		@Override
		public void mousePressed(MouseEvent e) {
			for(Triangle t : triangles) {
				int result = t.checkMouse(e.getX(), e.getY());
				if(result != 0) {
					triangleDragged = triangles.indexOf(t);
					moveState = result;
					triangles.get(lastTouched).setLastTouched(false);
					t.setLastTouched(true);
					lastTouched = triangles.indexOf(t);
					break;
				}
			}
		}
		
		@Override
		public void mouseExited(MouseEvent e) {}
		@Override
		public void mouseEntered(MouseEvent e) {}
		@Override
		public void mouseClicked(MouseEvent e) {}
	};
	private final MouseMotionListener mouseMotionListener = new MouseMotionListener() {
		@Override
		public void mouseMoved(MouseEvent e) {
		}
		@Override
		public void mouseDragged(MouseEvent e) {
			if(triangleDragged >= 0)
			{
				switch(moveState)
				{
					case 1: triangles.get(triangleDragged).setA(e.getX(),e.getY()); break;
					case 2: triangles.get(triangleDragged).setB(e.getX(),e.getY()); break;
					case 3: triangles.get(triangleDragged).setC(e.getX(),e.getY()); break;
					default: System.err.println("Should not ever have a moveState of 0 when triangleDragged is not 0 in TransformEditPanel"); System.exit(0); break;
				}
				repaint();
			}
		}
	};
	public TransformEditPanel(FlameModel model) {
		setModel(model);
		triangleDragged = -1;
		baseTriangle = new Triangle(null, this);
		addMouseListener(mouseListener);
		addMouseMotionListener(mouseMotionListener);
	}
	public void setModel(FlameModel model) {
		Color interesting[] = new Color[6];
		interesting[0] = Color.red;
		interesting[1] = Color.blue;
		interesting[2] = Color.green;
		interesting[3] = Color.yellow;
		interesting[4] = Color.magenta;
		interesting[5] = Color.cyan;
		int i = 0;
		this.model = model;
		triangles = new ArrayList<Triangle>();
		for(Function v : this.model.getFunctions()) {
			Triangle t = new Triangle(v.getAffineTransform(),this);
			t.setColor(interesting[i]);
			i++;
			triangles.add(t);
		}
		lastTouched = 0;
		triangles.get(0).setLastTouched(true);
	}
	@Override
	protected void paintComponent(Graphics g) {
		Graphics2D g2 = (Graphics2D)g;
		g2.setColor(Color.black);
		g2.fillRect(0, 0, getWidth(), getHeight());
		
		g2.setFont(new Font("Arial",Font.PLAIN,16));
		
		baseTriangle.draw(g2);
		
		Collections.reverse(triangles);
		for(Triangle t : triangles) {
			t.draw(g2);
		}
		Collections.reverse(triangles);
	}
	public ViewRectangle getViewRectangle() {
		return viewRectangle;
	}
	public int changeX(double x) {
		return viewRectangle.changeX(x);
	}
	public int changeY(double y) {
		return viewRectangle.changeY(y);
	}
	public double reverseX(int x) {
		return viewRectangle.reverseX(x);
	}
	public double reverseY(int y) {
		return viewRectangle.reverseY(y);
	}
	public void randomizeTriangles() {
		Random r = new Random();
		for(Triangle t : triangles) {
			t.setA(r.nextInt(getWidth()), r.nextInt(getHeight()));
			t.setB(r.nextInt(getWidth()), r.nextInt(getHeight()));
			t.setC(r.nextInt(getWidth()), r.nextInt(getHeight()));
		}
	}
	public void normallyRandomizeTriangles() {
		Random r = new Random();
		int ax, ay, bx, by, cx, cy;
		double ab, bc, ca;
		double area;
		for(Triangle t : triangles) {
			do {
				ax = r.nextInt(getWidth());
				ay = r.nextInt(getHeight());
				bx = r.nextInt(getWidth());
				by = r.nextInt(getHeight());
				cx = r.nextInt(getWidth());
				cy = r.nextInt(getHeight());
				area = area(ax, ay, bx, by, cx, cy);
				ab = dist(ax, ay, bx, by);
				bc = dist(bx, by, cx, cy);
				ca = dist(cx, cy, ax, ay);
			} while((area < 2000 || area > 10000) || ab > 400 || bc > 400 || ca > 400);
			t.setA(ax, ay);
			t.setB(bx, by);
			t.setC(cx, cy);
		}
	}
	public double area(double ax, double ay, double bx, double by, double cx, double cy) {
		double ab = dist(ax, ay, bx, by);
		double bc = dist(bx, by, cx, cy);
		double ca = dist(cx, cy, ax, ay);
		double s = (ab + bc + ca) / 2;
		return Math.sqrt(s * (s - ab) * (s - bc) * (s - ca));
	}
	public double dist(double x1, double y1, double x2, double y2) {
		double dx = x1 - x2;
		double dy = y1 - y2;
		return Math.sqrt(dx*dx + dy*dy);
	}
}
